package cn.bonoon.kernel.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import cn.bonoon.kernel.util.MD5Util;
import cn.bonoon.kernel.util.StringHelper;

public class StandardFileManager extends AbstractFileManager implements ServletContextAware, InitializingBean{
	private final static String DEFAULT_ROOT_DIRECTORY = /*separatorChar + */"/upload";
	private final static String DEFAULT_TEMPORARY_DIRECTORY = DEFAULT_ROOT_DIRECTORY + /*separatorChar + */"/temporary";
	private final static char separatorChar = '/';
	private ServletContext servletContext;
	
	//临时目录，如果需要先缓存到服务器再进行转移的，则需要使用到临时目录
	private String temporaryDirectory = DEFAULT_TEMPORARY_DIRECTORY;
	
	//根目录，即所有上传的文件，都会被放在这个根目录下面
	private String rootDirectory = DEFAULT_ROOT_DIRECTORY;
	
	private String baseDirectory;

	public void setRootDirectory(String rootDirectory) {
		this.rootDirectory = rootDirectory;
	}
	
	public void setTemporaryDirectory(String temporaryDirectory) {
		this.temporaryDirectory = temporaryDirectory;
	}
	
	private File root, temporary;
	
	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO 必要保存两个文件夹的存在
		root = new File(servletContext.getRealPath(rootDirectory));
		temporary = new File(servletContext.getRealPath(temporaryDirectory));
//		if(StringHelper.isEmpty(baseDirectory)){
//		}else{
//			root = new File(baseDirectory);
//			temporary = new File(baseDirectory, "/temporary");
//		}
		if(!root.isDirectory()){
			root.mkdirs();
		}
		if(!temporary.isDirectory()){
			temporary.mkdirs();
		}
	}
	
	@Override
	public void setServletContext(ServletContext sc) {
		this.servletContext = sc;
	}
	
	@Override
	public File[] listRoots() {
		return root.listFiles();
	}

	@Override
	public void openFile(HttpServletRequest request,
			HttpServletResponse response, String path, String name, String ext)
			throws Exception {

		SimpleFileInfo sfi = new SimpleFileInfo(servletContext, path, name, ext);
		response.setContentType(sfi.getContentType());
		sfi.readTo(response.getOutputStream());
	}
	
	@Override
	public void loadFile(HttpServletRequest request, HttpServletResponse response, String path, String name, String ext) throws Exception{
//		if (StringHelper.isEmpty(path)) {
//			throw new FileNotFoundException("文件不存在！");
//		}
//		if(StringHelper.isEmpty(name)){
//			int p = path.lastIndexOf('/');
//			if(p >= 0){
//				name = path.substring(p + 1);
//			}else{
//				name = path;
//			}
//		}else{
//			if(StringHelper.isEmpty(ext)){
//				int p = path.lastIndexOf('.');
//				if(p > 0){
//					ext = path.substring(p);
//				}
//			}
//			if(StringHelper.isNotEmpty(ext)){
//				if(!ext.startsWith(".")){
//					ext = "." + ext;
//				}
//				if(!name.endsWith(ext)){
//					name += ext;
//				}
//			}
//		}
		SimpleFileInfo sfi = new SimpleFileInfo(servletContext, path, name, ext);
		response.setContentType(SimpleFileInfo.DEFAULT_CONTENT_TYPE);
		response.setHeader("Content-Disposition", "attachment;fileName=" + sfi.getEncodeName());
		sfi.readTo(response.getOutputStream());
		//String fileFullPath = servletContext.getRealPath(path);
		//File fwq_file = new File(fileFullPath);
//		File lf = null;
//		if(fwq_file.exists()){
//			if(fwq_file.isFile()){
//				lf = fwq_file;
//			}else{
//				lf = new File(fwq_file, name);
//			}
//		}
//		if(null == lf || !lf.exists()){
//			throw new FileNotFoundException("文件不存在！");
//		}
//		InputStream inputStream = new FileInputStream(lf);
//		OutputStream outputStream = response.getOutputStream();
//		byte[] b = new byte[1024];
//		int length;
//		while ((length = inputStream.read(b)) > 0) {
//			outputStream.write(b, 0, length);
//		}
//		inputStream.close();
	}
	
	@Override
	public OutputStream openOutputStream(String path) throws FileNotFoundException{
		return new FileOutputStream(servletContext.getRealPath(path));
	}

	@Override
	public InputStream openInputStream(String path) throws FileNotFoundException {
		return new FileInputStream(servletContext.getRealPath(path));
	}

	@Override
	public File getFile(String path) {
		return new File(servletContext.getRealPath(path));
	}

	private String __parsePath(String dir, DirectoryStrategy strategy){
		String relativePath = rootDirectory;
		if(StringHelper.isNotEmpty(dir)){
			if(dir.charAt(0) != separatorChar){
				relativePath += separatorChar;
			}
			relativePath += dir;
		}
		
		relativePath = strategy.formatPath(relativePath);
		
		//判断将要保存文件的目录是否存在
		File saveDir = new File(servletContext.getRealPath(relativePath));
		if(!saveDir.isDirectory()){
			saveDir.mkdirs();
		}
		if(relativePath.charAt(relativePath.length() - 1) != separatorChar){
			relativePath += separatorChar;
		}
		return relativePath;
	}
	
	
	private FileInfo __parseFile(String relativePath, FilenameStrategy filenameStrategy, MultipartFile file) throws IOException {
		if(file.isEmpty())return null;
		FileInfo fi = new FileInfo(file.getOriginalFilename());
		switch (filenameStrategy) {
		case MD5:
			while(fi.savePath(servletContext, relativePath, MD5Util.randomMD5String()));
			break;
		case TIMESTAMP:
			while(fi.savePath(servletContext, relativePath, Long.toString(System.currentTimeMillis()))){
				try {//如果时间戳相同。。。那机率极小
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			break;
		default:
			int count = 0;
			String basename = fi.filename;
			while(fi.savePath(servletContext, relativePath)){
				fi.filename = basename + '(' + (count++) + ')';
			}
			break;
		}
		file.transferTo(fi.file);
		fi.size = file.getSize();
		fi.contentType = file.getContentType();
		fi.name = file.getName();
		return fi;
	}
	
	protected FileInfo __save(String dir, DirectoryStrategy directoryStrategy, FilenameStrategy filenameStrategy, MultipartFile file) throws IllegalStateException, IOException {
		String relativePath = __parsePath(dir, directoryStrategy);
		return __parseFile(relativePath, filenameStrategy, file);
	}

	protected FileInfo[] __save(String dir, DirectoryStrategy directoryStrategy, FilenameStrategy filenameStrategy, MultipartFile... files)throws IllegalStateException, IOException{
		String relativePath = __parsePath(dir, directoryStrategy);
		int len = files.length;
		FileInfo[] fis = new FileInfo[len];
		for(int i = 0; i < len; i++){
			fis[i] = __parseFile(relativePath, filenameStrategy, files[i]);
		}
		return fis;
	}

	protected FileInfo[] __save(String dir, DirectoryStrategy directoryStrategy, FilenameStrategy filenameStrategy, MultipartHttpServletRequest multipartRequest, String... filenames) throws IllegalStateException, IOException{
		String relativePath = __parsePath(dir, directoryStrategy);
		int len = filenames.length;
		FileInfo[] fis = new FileInfo[len];
		for(int i = 0; i < len; i++){
			MultipartFile file = multipartRequest.getFile(filenames[i]);
			if(null != file){
				fis[i] = __parseFile(relativePath, filenameStrategy, file);
			}
		}
		return fis;
	}

	public String getBaseDirectory() {
		return baseDirectory;
	}

	public void setBaseDirectory(String baseDirectory) {
		this.baseDirectory = baseDirectory;
	}
}
